package com.easipass.framework.eirframeworkcoredsl;

import java.util.List;

public class CheckPointedParseException extends ParseException {

    private int checkpointPointer = -1;

    private List<Token> tokens;

    private int tokenPointer;

    public CheckPointedParseException(String expressionString, int textPosition, int tokenPointer,
                                      int checkpointPointer, List<Token> tokens, DSLMessage message, Object... inserts) {
        super(expressionString, textPosition, message, inserts);
        this.tokenPointer = tokenPointer;
        this.checkpointPointer = checkpointPointer;
        this.tokens = tokens;
    }

    @Override
    public String getMessage() {
        StringBuilder s = new StringBuilder();
        if (message != null) {
            s.append(message.formatMessage(position, inserts));
        } else {
            s.append(super.getMessage());
        }
        int startOfLine = getStartOfLine(position);
        if (expressionString != null && expressionString.length() > 0) {
            s.append("\n").append(expressionString.substring(startOfLine)).append("\n");
        }
        int offset = position - startOfLine;
        if (checkpointPointer > 0 && offset >= 0 && (getStartOfLine(checkpointPointer) == startOfLine)) {
            int checkpointPosition = getCheckpointPosition();
            checkpointPosition = checkpointPosition - getStartOfLine(checkpointPosition);
            offset -= checkpointPosition;
            for (int i = 0; i < checkpointPosition; i++) {
                s.append(' ');
            }
            s.append("*");
            offset--;
        }
        if (offset >= 0) {
            for (int i = 0; i < offset; i++) {
                s.append(' ');
            }
            s.append("^\n");
        }
        return s.toString();
    }

    private int getStartOfLine(int position) {
        int lineStart = 0;
        for (int p = 0; p < position; p++) {
            if (expressionString.charAt(p) == '\n') {
                lineStart = p + 1;
            }
        }
        return lineStart;
    }

    public int getCheckpointPosition() {
        return checkpointPointer == 0 ? 0 : tokens.get(checkpointPointer - 1).endPos;
    }

    public String getExpressionStringUntilCheckpoint() {
        return expressionString.substring(0, getCheckpointPosition());
    }

    public int getCheckpointPointer() {
        return checkpointPointer;
    }

    public List<Token> getTokens() {
        return tokens;
    }

    public int getTokenPointer() {
        return tokenPointer;
    }

}
